#include "JingleManager.h"
#include "BaseNotification.h"
#include "JingleSessionFactory.h"
#include "clientbase.h"

namespace cm_nat
{
    using namespace cm_base;
    using namespace cm_xmpp;

    JingleManager::JingleManager()
        : m_parent(NULL),
        m_stopFlag(false),
        m_listener(NULL),
        m_jingleHandler(NULL)
    {

    }

    JingleManager::~JingleManager()
    {

    }

    int JingleManager::setup( ClientBase* p_parent )
    {
        m_parent = p_parent;
        m_jid = m_parent->jid();

        if( !m_jingleHandler ){
            m_jingleHandler = new Jingle( m_parent, this );
        }
        
        //start processing jingle extensions
        m_thread.start( *this );

        return CM_RES_SUCCESS;
    }

    int JingleManager::teardown()
    {
        if( m_jingleHandler ){
            delete m_jingleHandler;
        }
        return CM_RES_SUCCESS;
    }

    void JingleManager::registerListener(JingleManagerListener* p_listener )
    {
        m_listener = p_listener;
    }


    bool JingleManager::addJingleSession( JingleSession* p_js )
    {
        //check if exist
        if( findJingleSession(p_js->m_sid) ){
            return false;
        }else{
            m_jingleSessions[p_js->m_sid] = p_js;
            p_js->setJingleManager( this );
            return true;
        }
    }

    bool JingleManager::removeJingleSession( JingleSession* p_js )
    {
        JingleSessionIdMap::iterator t;
        JingleSessionIdMap::iterator it = m_jingleSessions.begin();
        while( it != m_jingleSessions.end() )
        {
            t = it;
            ++it;
            if( p_js == (*t).second )
                m_jingleSessions.erase( t );
        }

        return true;
    }

    JingleSession* JingleManager::findJingleSession(std::string sid)
    {
        JingleSessionIdMap::const_iterator it= m_jingleSessions.find( sid );
        if( it == m_jingleSessions.end() ){
            return NULL;
        }else{
            return (*it).second;
        }
    }

    
    void JingleManager::send(IQ &iq)
    {
        m_parent->send( iq, m_jingleHandler, false );
    }

    void JingleManager::onJingleTag(const Tag* p_je)
    {
        BaseNotification* p_en = new BaseNotification;
        p_en->setType(EVENT_INCOMING_JINGLE_TAG);
        p_en->setData( (void*)p_je );

        m_queue.enqueueNotification(p_en,0);
    }

    bool JingleManager::processJingleTag(const Tag* p_tag)
    {
        bool res = false;

        if( p_tag->name()!= "jingle" )
            return false;

        std::string action = p_tag->findAttribute("action");
        
        if( action == "session-initiate")
        {
            res = processInitiateAction(p_tag);
        }
        else if( action == "session-terminate")
        {
            res = processTerminateAction(p_tag);
        }
        else
        {
            res = processSessionActions(p_tag);
        }

        return true;
    }

    bool JingleManager::processInitiateAction(const  Tag* p_tag )
    {
        std::string sid = p_tag->findAttribute("sid");

        JingleSession* p_js = findJingleSession( sid );
        if( p_js ){
            //same sid exist
            return false;
        }

        p_js = JingleSessionFactory::createSession(SESSION_MEDIA);
        p_js->setJID( m_jid );

        std::string initiator = p_tag->findAttribute("initiator");
        p_js->setPeerJID( JID(initiator) );
        p_js->setSessionID( sid );

        addJingleSession(p_js);
      
        //notify listener
        if( m_listener ){
            m_listener->onSessionInitiate( p_js );
        }

        p_js->parseJingleTag(p_tag);

        return true;
    }

    bool JingleManager::processTerminateAction(const  Tag* p_tag )
    {
        std::string sid = p_tag->findAttribute("sid");

        JingleSession* p_js = findJingleSession( sid );
        if( !p_js ){
            return false;
        }
        removeJingleSession(p_js);

        if( m_listener ){
            m_listener ->onSessionTerminate(p_js);
        }

        return true;;
    }

    bool JingleManager::processSessionActions(const  Tag* p_tag )
    {
        std::string sid = p_tag->findAttribute("sid");

        JingleSession* p_js = findJingleSession(sid);
        if( !p_js ){
            return false;
        }

        p_js->parseJingleTag( p_tag );

        return true;
    }

    void JingleManager::run()
    {
        BaseNotification* p_event = NULL;

        while( !m_stopFlag )
        {
            p_event = (BaseNotification* )m_queue.waitDequeueNotification();

            switch( p_event->getType() )
            {
            case EVENT_INCOMING_JINGLE_TAG:
                {
                    Tag* p_tag = (Tag*)p_event->getData(); 
                    processJingleTag(p_tag);
                    delete p_tag;

                    p_event->release();
                }
                break;

            default:
                p_event->release();
            }
        }

    }
}